package com.zrc.japktool.apk.merge;

import pxb.android.Res_value;
import pxb.android.arsc.*;
import pxb.android.axml.Util;
import com.zrc.japktool.util.FileUtil;
import com.zrc.japktool.util.Zip4jUtil;

import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;

/**
 * ARSC文件编辑器，支持对APK中的resources.arsc进行编辑操作
 */
public class ResGuard {

    public static class Name {
        private  final String LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
        private  final String DIGITS_AND_LETTERS = "0123456789" + LETTERS;
        private  final int MIN_LENGTH = 3;
        private  int MAX_LENGTH = 6; // 可调整最大长度
        private  final Random random = new Random();
        private  Set<String> generatedNames = new HashSet<>();

        public String next() {
            String name;
            do {
                // 随机决定名称长度(6-MAX_LENGTH)
                int length = MIN_LENGTH + random.nextInt(MAX_LENGTH - MIN_LENGTH + 1);

                // 首字符必须是字母
                char firstChar = LETTERS.charAt(random.nextInt(LETTERS.length()));

                // 生成剩余字符
                StringBuilder sb = new StringBuilder();
                sb.append(firstChar);
                for (int i = 1; i < length; i++) {
                    char c = DIGITS_AND_LETTERS.charAt(random.nextInt(DIGITS_AND_LETTERS.length()));
                    sb.append(c);
                }
                name = sb.toString();

            } while (generatedNames.contains(name)); // 确保不重复

            generatedNames.add(name);
            return name;
        }

    }

    /**
     * 打印resources.arsc的详细信息
     */
    public static void apkResGuard(String apkPath) throws IOException {
        String apkParentPath = new File(apkPath).getParent();
        String apkAllName = new File(apkPath).getName();
        String apkName = apkAllName.replace(".apk","");
        File cacheDir = Files.createTempDirectory(new File(apkParentPath).toPath(), apkName).toFile();
        Map<String,String> resPathMap = new HashMap<>();
        Zip4jUtil.unzip(apkPath,cacheDir.getAbsolutePath());

        try {
            byte[] buffer =  Util.readFile(new File(cacheDir,"resources.arsc"));
            List<Pkg> pkgs= new ArscParser(ByteBuffer.wrap(Objects.requireNonNull(buffer))).parse();;
            Name name = new Name();
            for (int i = 0; i < pkgs.size(); i++) {
                Pkg pkg = pkgs.get(i);
                for (Type type : pkg.types.values()) {
                    if (type==null) continue;
                    for (ResSpec spec : type.specs) {
                        if (spec==null) continue;
                        String newName =name.next();
                        spec.name = newName;//混淆资源名称

                        for (Config config : type.configs) {
                            if (config==null) continue;
                            ResEntry entry = config.resources.get(spec);
                            if (entry != null) {
                                if (entry.value instanceof Res_value) {
                                    if (((Res_value) entry.value).raw==null)continue;
                                    if (((Res_value) entry.value).raw.contains(".")
                                            &&!type.name.equals("id")
                                            &&!type.name.equals("style")
                                            &&!type.name.equals("string")){
                                        String fileName = new File(entry.value.toString()).getName();
                                        String parentPath = new File(entry.value.toString()).getParent();
                                        String filePath = entry.value.toString();
                                        int inDex = fileName.indexOf(".");
                                        String oldName = fileName.substring(0,inDex);
                                        String suffix = fileName.substring(inDex);
                                        //System.out.println(fileName+"---------"+oldName+"---------"+suffix+"------------"+type.name);
                                        //entry.value = Res_value.newStringValue(newName+suffix);
                                        entry.value = Res_value.newStringValue(entry.value.toString().replace(oldName, newName));
                                        //System.out.println("spec: " + spec.name + " value: " + entry.value);
                                        //System.out.println("------------"+filePath);

                                        //开始混淆apk中res目录下的资源文件名称
                                        //byte[] fileBytes = Zip4jUtil.readFileBytes(apkPath, filePath);
                                        //filePath:  res/xml/util_code_provider_paths.xml的样式
                                        //Zip4jUtil.delFile(apkPath, filePath);
                                        //Zip4jUtil.writeFileBytes(apkPath,  entry.value.toString(), fileBytes);

                                        resPathMap.put(filePath,entry.value.toString());
                                    }
                                }
                            }
                        }
                    }
                }
            }

            for (Map.Entry<String, String> path : resPathMap.entrySet()) {
                File fileTo = new File((cacheDir.getAbsolutePath()+"/"+path.getValue()).replace("\\","/"));
                new File((cacheDir.getAbsolutePath()+"/"+path.getKey()).replace("\\","/")).renameTo(fileTo);
            }

            // 将修改后的resources.arsc文件写入apk中
            ArscWriter writer = new ArscWriter(pkgs);
            byte[] newData = writer.toByteArray();
            Util.writeFile(newData,new File(cacheDir,"resources.arsc"));
            String outApkPaht = Files.createTempFile(Paths.get(apkParentPath),apkName,".apk").toAbsolutePath().toString().replace("\\","/");
            Zip4jUtil.compressFolderWithNested(cacheDir.getAbsolutePath()+"/",outApkPaht,false);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if (cacheDir.exists()) {
                FileUtil.delDir(cacheDir);
            }
        }
    }

    public static void main(String[] args) throws Exception{
        ResGuard.apkResGuard("C:/Users/Administrator/Desktop/test/demo.apk");
    }

}